home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / applications / wp / dvi2lj.lha / tfm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-14  |  7.4 KB  |  258 lines

  1. /* tfm.c -- read tfm widths resident font support in dvilj. Originally
  2.    written by kb@cs.umb.edu in early 1994. Public domain. */
  3.  
  4. #include "config.h" /* for STRSIZE and tfm_info_type, at least */
  5. #include <stdio.h>
  6.  
  7. #ifdef KPATHSEA
  8. #include <kpathsea/config.h>
  9. #include <kpathsea/c-fopen.h>
  10. #include <kpathsea/lib.h>
  11. #include <kpathsea/tex-file.h>
  12. #else
  13. extern char* TFMpath;
  14. #endif
  15.  
  16. #ifdef vms
  17. #include <ssdef.h>
  18. #include <stsdef.h>
  19. #define getenv vms_getenv
  20. #endif
  21.  
  22. /* Defined in dvi2xx.c. */
  23. extern long NoSignExtend ();
  24. #define TFM_GET_TWO()  NoSignExtend (tfm_fp, 2)
  25. #define TFM_GET_FOUR() NoSignExtend (tfm_fp, 4)
  26.  
  27. extern bool G_quiet;
  28. extern void Warning();
  29.  
  30. /* Defined in xmalloc.c. */
  31. extern void *xmalloc ();
  32.  
  33.  
  34.  
  35. /* Read N words (N * 4 bytes) from TFM_FP and return it in *OUTBUF, unless
  36.    OUTBUF==NULL, in which case throw them away. */
  37.  
  38. static void
  39. tfm_get_n (tfm_fp, nwords, outbuf)
  40.     FILE *tfm_fp;
  41.     unsigned nwords;
  42.     void **outbuf;
  43. {
  44.   unsigned n = nwords * 4;
  45.   void *buf = (void *) xmalloc (n);
  46.  
  47.   if (fread (buf, n, 1, tfm_fp) != 1) {
  48.     fprintf (stderr, "dvi2xx: Could not read %u bytes from TFM file.\n", n);
  49.     exit (1);
  50.   }
  51.  
  52.   /* If OUTBUF is null, free what we just read, else return it. */
  53.   if (outbuf) {
  54.     *outbuf = buf;
  55.   } else {
  56.     free (buf);
  57.   }
  58. }
  59.  
  60.  
  61. /* Read a string in BCPL format from DATA into STR, and terminate with a
  62.    null byte. First byte of DATA says how many characters follow.
  63.    Assume STR is long enough.  */
  64.  
  65. static void
  66. get_bcpl (data, str)
  67.     unsigned char *data;
  68.     unsigned char *str;
  69. {
  70.   unsigned length;
  71.   
  72.   for (length = *(data ++); length; length --) {
  73.     *(str ++) = *(data ++);
  74.   }
  75.  *str = 0;
  76. }
  77.  
  78. /* Header word 18:
  79.      2 bytes: "KN" for Karl and Norm---this identifies our extensions
  80.      1 byte : 1 if proportional, 0 otherwise
  81.      1 byte : reserved (to extend the style, if necessary)
  82.    Header word 19:
  83.      2 bytes: PCL style selection number
  84.      1 byte : reserved (to extend weight, if necessary)
  85.      1 byte : weight (signed, 2's complement, valid -7 to +7)
  86.    Header word 20:
  87.      2 bytes: reserved (to extend typeface id, if necessary)
  88.      2 bytes: PCL typeface selection number
  89.    
  90.    The first (BigEndian) byte of header word #18 is DATA[0].
  91.    Assume DATA is long enough for everything we might try to read. */
  92.  
  93. static bool
  94. get_pcl_info (data, spacing, style, weight, typeface_id)
  95.     unsigned char *data;
  96.     unsigned *spacing;
  97.     unsigned *style;
  98.     int *weight;
  99.     unsigned *typeface_id;
  100. {
  101.   /* No magic number for our extensions => forget it. */
  102.   if (data[0] != 'K' && data[1] != 'N')
  103.     return _FALSE;
  104.  
  105.   *spacing = data[(0* 4) + 2]; /* Third byte of first word. */
  106.   
  107.   /* First two bytes of second word. */
  108.   *style = (data[(1 * 4)] << 8) + data[(1 * 4) + 1];
  109.   
  110.   /* Last byte of second word, signed two-complement. */
  111.   *weight = data[(1 * 4) + 3];
  112.   if (*weight >= 128) *weight -= 256;
  113.   
  114.   /* Effectively all four bytes of third word. */
  115.   *typeface_id = (data[(2 * 4) + 0] << 24) + (data[(2 * 4) + 1] << 16)
  116.                + (data[(2 * 4) + 2] << 8)  + (data[(2 * 4) + 3]);
  117.  
  118.   return _TRUE;
  119. }
  120.  
  121. /* If the TFM file NAME exists, set the elements of RET and return true.
  122.    Otherwise, return false.  */
  123.  
  124. bool
  125. tfm_read_info (name, ret)
  126.     char *name;
  127.     tfm_info_type *ret;
  128. {
  129.   /* Don't use a structure for this, since then it might occupy more
  130.      than the exactly four bytes that we need. */
  131.   unsigned char *char_info;
  132.   FILE *tfm_fp;
  133.   unsigned char *header_data;
  134.   unsigned char *width_raw; /* array of 1-byte data */
  135.   unsigned long *width_table; /* array of 4-byte fixes */
  136.   unsigned i;
  137.   unsigned lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np;
  138.  
  139. #ifndef KPATHSEA
  140.   char full_name[STRSIZE];
  141.   if (findfile(TFMpath, name, NULL, full_name, _TRUE, 0)) {
  142.  
  143.     /* fprintf(stderr,"full_name=<%s>\n", full_name);*/
  144.     tfm_fp = fopen (full_name, READ_BINARY);
  145.     if (tfm_fp == NULL) {
  146.       /* this can happen, if the calculation for max number of open
  147.        * files has to be corrected
  148.        */
  149.       fprintf(stderr,"Error: file <%s> could not be opened\n", full_name);
  150.       return _FALSE;
  151.     }
  152.   } else {
  153.     Warning("tfm file %s.tfm not found on path <%s>\n", name, TFMpath);
  154.     return _FALSE;
  155.   }
  156. #else
  157.   char *full_name = kpse_find_tfm (name);
  158.  
  159.   if (full_name == NULL) {
  160.     return _FALSE;
  161.   }
  162.   tfm_fp = xfopen (full_name, FOPEN_RBIN_MODE);
  163. #endif
  164.  
  165.   (void) TFM_GET_TWO ();   /* word length of file */
  166.   lh = TFM_GET_TWO ();     /* words of header data */
  167.   bc = TFM_GET_TWO ();     /* smallest character code */
  168.   ec = TFM_GET_TWO ();     /* largest character code */
  169.   nw = TFM_GET_TWO ();     /* words in width table */
  170.   nh = TFM_GET_TWO ();     /* words in height table */
  171.   nd = TFM_GET_TWO ();     /* words in depth table */
  172.   ni = TFM_GET_TWO ();     /* words in italic correction table */
  173.   nl = TFM_GET_TWO ();     /* words in lig/kern table */
  174.   nk = TFM_GET_TWO ();     /* words in kern table */
  175.   ne = TFM_GET_TWO ();     /* words in extensible char table */
  176.   np = TFM_GET_TWO ();     /* words of font parameter data */
  177.  
  178.   tfm_get_n (tfm_fp, lh, &header_data);
  179.   /* Only two headerbyte words are required by the TFM format, so don't
  180.      insist on all this extra stuff. */
  181.   if (lh > 2) {
  182.     get_bcpl (header_data + (2 * 4), ret->coding_scheme);
  183.   } else {
  184.     ret->coding_scheme[0] = 0;
  185.   }
  186.   
  187.   if (lh > 12) {
  188.     get_bcpl (header_data + (12 * 4), ret->family);
  189.   } else {
  190.     ret->family[0] = 0;
  191.   }
  192.  
  193.   /* Sorry for the convoluted logic. The idea is that if the family
  194.      is HPAUTOTFM, we better have our extensions -- so if we don't
  195.      have enough header words, or if we don't find what we need in
  196.      the header words, something's seriously wrong, and we shouldn't
  197.      claim to have succeeded at reading a good TFM file.  */
  198.  
  199.   if (strcmp (ret->family, "HPAUTOTFM") == 0
  200.       && (lh < 20
  201.           || !get_pcl_info (&(header_data[18 * 4]),
  202.                             &ret->spacing, &ret->style, &ret->weight,
  203.                             &ret->typeface_id))) {
  204.       fclose (tfm_fp);
  205.       return _FALSE;
  206.   }
  207.  
  208.   /* Initialize our returned array of widths to zero, since the TFM file
  209.      need not contain info for all character codes. */
  210.   for (i = 0; i < bc; i++) {
  211.     ret->widths[i] = 0;
  212.   }
  213.   for (i = ec + 1; i < 256; i++) {
  214.     ret->widths[i] = 0;
  215.   }
  216.   
  217.   /* The char_info is one word (four bytes) for each character in the font. */
  218.   tfm_get_n (tfm_fp, ec - bc + 1, &char_info);
  219.   
  220.   /* The width table is just nw words. */
  221.   tfm_get_n (tfm_fp, nw, &width_raw);
  222.   width_table = (unsigned long *) xmalloc (nw * 4);
  223.  
  224.   /* But the width table contains four-byte numbers, so have to convert
  225.      from BigEndian to host order. */
  226.   for (i = 0; i < nw; i++) {
  227.     unsigned byte_offset = i * 4;
  228.     unsigned b1 = width_raw[byte_offset];
  229.     unsigned b2 = width_raw[byte_offset + 1];
  230.     unsigned b3 = width_raw[byte_offset + 2];
  231.     unsigned b4 = width_raw[byte_offset + 3];
  232.     width_table[i] = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
  233.   }
  234.  
  235.   /* For each character, retrieve and store the TFM width. */
  236.   for (i = bc; i <= ec; i++) {
  237.     unsigned char w_i = char_info[(i - bc) * 4];
  238.     ret->widths[i] = width_table[w_i];
  239.   }
  240.  
  241.   /* Throw away everything up to the second font parameter. (Could just
  242.      seek, but I don't want to pull in the include files, etc.) */
  243.   if (np >= 2) {
  244.     tfm_get_n (tfm_fp, nh + nd + ni + nl + nk + ne + 1, NULL);
  245.     ret->interword = TFM_GET_FOUR ();
  246.   } else {
  247.     ret->interword = 0;
  248.   }
  249.  
  250.   free (header_data);
  251.   free (char_info);
  252.   free (width_raw);
  253.   free (width_table);
  254.   
  255.   fclose (tfm_fp);
  256.   return _TRUE;
  257. }
  258.